﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Xml;
/// <summary>
/// 这个文件包含了运控类的接口封装
/// parti和part5,还有io接口.
/// </summary>
namespace IndustryWrapper
{
    /// <summary>
    /// IO控制的通用1
    /// </summary>
    public interface IIoPart
    {
        /// <summary>
        /// 新版本的IO指令,为了简化和兼容所有的IO类型
        /// 这个是立即指令,IO模块的属性访问相区别
        /// 属性访问数据访问静态数组中的值,后台周期刷新
        /// 可以用来读输入点和输出点。
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        bool MC_GetIO(ref CIO_Di data);
        /// <summary>
        /// 获取输出点当前值
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        bool MC_GetIO(CIO_Do data);
        /// <summary>
        /// 获取模拟量得输入
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        float MC_GetIO(CIO_Ai data);
        /// <summary>
        /// 获取模拟量得输出当前值
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        float MC_GetIO(CIO_Ao data);
        /// <summary>
        /// 获取编码器的值
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        long MC_GetIO(CIO_Enc data);
        /// <summary>
        /// 新版本的IO指令,为了简化和兼容所有的IO类型
        /// 这个是立即指令,IO模块的属性访问相区别
        /// 属性访问数据访问静态数组中的值,后台周期刷新
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        bool MC_SetDo(CIO_Do data,bool value);
        /// <summary>
        /// 新版本的IO指令,为了简化和兼容所有的IO类型
        /// 这个是立即指令,IO模块的属性访问相区别
        /// 属性访问数据访问静态数组中的值,后台周期刷新
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        bool MC_SetDo(CIO_Ao data, float value);
        /// <summary>
        /// 获取整个IO模块的值
        /// 用来内部刷新的时候做批量调用
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        bool MC_GetModel(CIoModel data);
        ///// <summary>
        ///// 读取整个模块的 输入 输出数据全部堵回来
        ///// </summary>
        ///// <param name="m"></param>
        ///// <returns>返回读取成功与否</returns>
        //bool getIoModel(ref CIoModel m);
        ///// <summary>
        ///// 读取单个输入点
        ///// </summary>
        ///// <param name="input"></param>
        ///// <returns></returns>
        //bool getDi(ref CIO_Di input);
        ///// <summary>
        ///// 读取一个输出点的值
        ///// </summary>
        ///// <param name="output"></param>
        ///// <returns></returns>
        //bool getDo(ref CIO_Do output);
        ///// <summary>
        ///// 某一个输出
        ///// </summary>
        ///// <param name="output">输出的参数</param>
        ///// <param name="value">输出的值TRUE OR FALSE</param>
        ///// <param name="reverse">反转 =true的时候会自动读取当前值,然后取反输出</param>
        ///// <returns>设置成功</returns>
        //bool setDo(CIO_Do output, bool value,bool reverse = false);
    }
    /// <summary>
    /// 一些建议组件  都要初始化反初始化和刷新
    /// </summary>
    public interface IInitModel
    {
        bool Init();                     //初始化
        bool UnInit();                   //反初始化
    }
    public interface IReadAndSave
    {
        bool Read(string xml);
        bool Save(string xml);
    }
    /// <summary>
    /// 刷新模块 
    /// </summary>
    public interface IFreshModel
    {
        void Fresh();                    //刷新状态
        void Run();                      //运行中
    }
    /// <summary>
    /// 启停模块
    /// </summary>
    public interface IStartStopModel
    {
        bool Start();
        bool Stop();
        bool Pause();
        bool Reset();
    }
    /// <summary>
    /// 运动控制的1
    /// </summary>
    public interface IMotionPartI
    {
        int MC_PowerOff(CAxisRef axis); //关闭伺服
        int MC_PowerOn(CAxisRef axis);    //开电
        int MC_Reset(CAxisRef axis);    //复位
        int MC_Home(ref CAxisRef axis);     //回零
        int MC_HomeStatus(ref CAxisRef axis);//回零的状态
        int MC_MoveAbs(CAxisRef axis, double tpos, double beilv = 0.5);
        int MC_MoveAdd(CAxisRef axis, double dist, double beilv = 0.5);
        int MC_MoveJog(CAxisRef axis, double beilv = 0.5);
        /// <summary>
        /// 这个是立即读取指令
        /// 普通情况下请用轴状态来访问
        /// </summary>
        /// <param name="axisref"></param>
        /// <returns></returns>
        int MC_AxisRef(ref CAxisRef axisref);
        /// <summary>
        /// 读取整个轴组的状态
        /// 一次读取多个,一般用于底层刷新数据
        /// </summary>
        /// <param name="prm"></param>
        /// <returns></returns>
        int MC_AxisRef(CAxisModelPrm prm);
        int MC_EStop(CAxisRef axis);
        int MC_SetPos(CAxisRef axis, double pos);
        /// <summary>
        /// 设置轴的参数,不同控制器会不同
        /// </summary>
        /// <param name="axisPrm"></param>
        /// <returns></returns>
        int MC_SetAxisParameter(CAxisSinglePrm axisPrm);
    }
    /// <summary>
    /// 运动控制的5 
    /// </summary>
    public interface IMotionPartII
    {
        /// <summary>
        /// 原生的插补运动G代码
        /// 一次执行一条命令
        /// 这个指令是基于插补缓冲区坐标系
        /// </summary>
        /// <param name="crd">坐标系参数</param>
        /// <param name="cmd">命令字符串</param>
        /// <returns></returns>
        int MC_CrdData(string crdID,string cmd);         
        /// <summary>
        /// 一次运行很多个指令 
        /// 标准的G代码 先只做了运动部分
        /// 如果超过了范围 就启动线程继续查看刷新
        /// </summary>
        /// <param name="crd"></param>
        /// <param name="gcode"></param>
        /// <param name="start">是否启动</param>
        /// <returns></returns>
        int MC_CrdData(string crdID, List<string> gcode);
        /// <summary>
        /// 检测这个制定坐标系是否建立
        /// </summary>
        /// <param name="crd"></param>
        /// <returns>=0表示坐标系不存在 >0表示存在</returns>
        int MC_CrdCheckExist(string crdID);
        /// <summary>
        /// 创建坐标系
        /// </summary>
        /// <param name="crd"></param>
        /// <returns> = 0表示创建成功</returns>
        int MC_CrdCreate(string crdID);
        
        int MC_CrdStatus(ref CCrdPrmSingle crd);
        int MC_CrdStart(string crdID);
        int MC_CrdPause(string crdID);
        int MC_CrdStop(string crdID);
        /// <summary>
        /// 缓冲区命令
        /// 解析缓冲区的指令  内部会一行一行的执行
        /// </summary>
        /// <param name="cmdList"></param>
        /// <returns></returns>
        int MC_BuffControl(List<string> cmdList);
    }
    /// <summary>
    /// 轴组的运动类型
    /// </summary>
    public enum EMotionGroup
    {
        D2Motion=0,
        D3Motion=1,
        D4Motion=2,
        D5Motion=3,
        SCara=4,
        Delta=5,
        R6=6
    }
    /// <summary>
    /// 轴组运动类型
    /// 插补运动的超集
    /// </summary>
    public interface IMotionGroup
    {
        int MC_CreateGroup(EMotionGroup tp);
        int MC_DelGroup(EMotionGroup tp);
        int MC_Move(EMotionGroup tp);
    }

    /// <summary>
    /// 特殊的定义
    /// </summary>
    public interface IMotionPartSpecial
    {
        //int MC_Capture(CAxisRef axis);
        int compare();
        int MC_Compare(CAxisRef axis, double posMM, CIO_Do cmpInput);
    }

    /// <summary>
    /// 绝对值编码器的处理
    /// </summary>
    [Serializable]
    public class IAbsEncBase
    {
        public EAbsEncType encType = EAbsEncType.COM232;
        public SerialPort port = null;//232串口号
        public double abcCircle = 0, absEncSingle = 0;
        public virtual int read(ref CAxisRef axis)
        {
            return 0;
        }
    }
    /// <summary>
    /// COPLEY的绝对值编码器读写
    /// </summary>
    public class CCopleyAbcEnc:IAbsEncBase
    {
        public int readStatus = 0;//读写状态 1=正在读写 2=读取成功 -1 = 读写超时 -2 读取失败
        public double absEncPos = 0;
        private SerialPort port = null;//232串口号
        private string portName = "COM1";
        public CCopleyAbcEnc(string portName)
        {
            this.portName = portName;
            this.port = new SerialPort(portName);
            //波特率
            port.BaudRate = 9600;
            //数据位
            port.DataBits = 8;
            //两个停止位
            port.StopBits = System.IO.Ports.StopBits.One;
            //无奇偶校验位
            port.Parity = System.IO.Ports.Parity.None;
            port.ReadTimeout = 100;
            port.WriteTimeout = -1;

            port.DataReceived += new SerialDataReceivedEventHandler(Port_DataReceived);
        }

        private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(50);
            UTF8Encoding utf8 = new UTF8Encoding();// 显示汉字与字符
            if (port.BytesToRead > 0)
            {
                byte[] readBytes = new byte[port.BytesToRead];
                port.Read(readBytes, 0, readBytes.Length);
                string str = utf8.GetString(readBytes);
                if (str.IndexOf("v") >= 0)
                {
                    string numStr = str.Replace("v", "");
                    numStr = numStr.Replace(" ", "");
                    absEncPos = double.Parse(numStr);
                    readStatus = 2;
                }
                else
                {
                    readStatus = -1;
                }
                port.Close();
            }
        }

        public override int read(ref CAxisRef axis)
        {
            if (port == null)
                return -1;
            try
            {
                port.Open();
            }
            catch (Exception)
            {
                return -1;
            }
            if (!port.IsOpen)
                return -2;
            //读取绝对值的实际位置.
            readStatus = 1;
            byte[] data = System.Text.Encoding.ASCII.GetBytes("g r0x32\r");
            port.Write(data, 0, data.Length);
            int maxcounte = 0;
            while (readStatus != 2 && readStatus != -1 && ++maxcounte < 500)
            {
                Thread.Sleep(1);//延迟100ms
            }
            int rst = 0;
            if (readStatus == 2)
            {
                axis.prm.absEncPosByRead = absEncPos;
                rst = 0;
            }
            else if (true)
            {
                rst = -1;
            }
            if (port.IsOpen)
                port.Close();
            return rst;
        }
    }
}
